pmatch
When we had our first look at the structs, we hinted at the possibility of custom control flows.
These are possible thanks to the pmatch
construct.
To understand why this is extremely useful, let's take our Toy
struct we defined looking at pstruct
.
const Toy = pstruct({
Stick: {},
Ball: {
size: int,
isSoft: bool
},
Mailman: {
name: str,
age: Age.type
}
})
And let's say we want to have a function that extracts the name of the mailman our dog plays with when we're out. It would look something like this:
const getMailmanName = plam( Toy.type, str )
( toy =>
pmatch( toy )
.onMailman( mailman => mailman.name )
.onStick( _ => pStr("") )
.onBall( _ => pStr("") )
)
pmatch
is taking a struct Term
and returns a Typescript object with all the names of possible constructors that struct has, based on its definition.
It then executes the branch based on the constructor used to get the struct instance.
A pmatch
branch gets as input the instance of the struct with all fields aviable trough dot notation.
This way the defined function returns the name of the mailman if the Toy was actually constructed using the Mailman
constructor; otherwise it returns an empty string.
The underscore (_
) wildcard
pmatch
will force you to cover the cases for all constructors; but many times we only want to do something if the struct was built using one specific constructor without regard for any other constructors.
In fact we found ourselves in a very similar case in the example above: we want to do something only in the Mailman
case but not in the others.
For situations like these there is the underscore (_
) wildcard, that allows us to rewrite our function as follows:
const getMailmanName = plam( Toy.type, str )
( toy =>
pmatch( toy )
.onMailman( mailman => mailman.name )
._( _ => pStr("") )
)
This not only makes the code more readable but in the vast majority of the cases it also makes it more efficient!
Inline dot notation
Now that we have a way to extract the name of the mailman from a Toy, we need to pass the actual toy to the function we just defined.
Using the pmatch
function, our code would look like this:
// remember the definition of `Dog`
const Dog = pstruct({
Dog: {
name: str,
age: Age.type,
favouriteToy: Toy.type
}
});
const getMailmanNameFromDog = plam( Dog.type, str )
( dog =>
pmatch( dog )
.onDog( dogInstance =>
getMailmanName.$( dogInstance.favouriteToy )
)
)
This works just fine but is a lot of code just to get a field of a constructor we know is unique.
Fortunately for us, if the struct definition has only one possible constructor, this struct term directly exposes the fields; so that we can threat it as a normal javascript object
This allows us to rewrite the function as
const getMailmanNameFromDog = plam( Dog.type, str )
( dog =>
getMailmanName.$( dog.favouriteToy )
)
which is a lot cleaner!